/*
 * SoftwareSAR - 1.0
 */
package br.com.cpqd.ssar.processamento;

import br.com.cpqd.ssar.utilitarias.FonteEletromagnetica;
import br.com.cpqd.ssar.utilitarias.FonteEletromagneticaSimulacao;
import br.com.cpqd.ssar.utilitarias.ListaFontesEletromagneticasSimulacao;
import br.com.cpqd.ssar.utilitarias.ListaFontesEletromagneticas;
import br.com.cpqd.ssar.utilitarias.Vertice;
import br.com.cpqd.ssar.utilitarias.RelatorioPosProcessamento;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Gerenciar a criação dos arquvos necessários a simulação com o FDTD 3D
 * @author Carlos Henrique da Silva Santos
 * @version 1.0
 */
public class ControladorConfiguracoesProcessamento {

    /*
     * Lista de Fontes Eletromagneticas do Usuario
     */
    ListaFontesEletromagneticas listaFontes;
    
    /*
     * Lista de Fontes Eletromagneticas inseridas na simulacao
     */
    ListaFontesEletromagneticasSimulacao listaFontesEletromagnetciasSimulacao;
    /*
     * Caminho de entrada do FDTD
     */
    String enderecoEntradaFDTD;
    /*
     * Caminho de saida dos arquivos Gerados pelo FDTD
     */
    String enderecoSaidaFDTD;
    /*
     * Indica quais sao os limites da simulacao (coordenadas espaciais)
     * MinX 
     */
    Vertice[] limitesSimulacao;

    /*
     * Quantidade de Celulas utilizadas na discretizacao X,Y,Z
     */
    Vector discretizacaoSimulacao;
    /*
     * Valores dos Deltas Espaciais em X,Y,Z
     */
    Vector deltaSimulacao;
    /*
     * Quantidade de passos de tempo a serem executado pelo FDTD
     */
    private int nmax;
    /*
     * Configuracoes da PML
     */
    Vector pml;

    /**
     * Armazena a listagem de relatorios a serem gerados
     */
    Vector listaRelatorios;

    /*
     * Construtor
     */
    public ControladorConfiguracoesProcessamento() {
        limitesSimulacao        = new Vertice[2];
        pml                     = new Vector();
        discretizacaoSimulacao  = new Vector();
        deltaSimulacao          = new Vector();    
    }

    /* Tem que receber os dados de cada relatorio */
    private boolean gerarArquivoRelatorio(){
        try {
            int contRelatorio, contParametros;
            FileWriter filewriter               = new FileWriter(this.enderecoEntradaFDTD + "_reports.isar");
            PrintWriter printwriter             = new PrintWriter(new BufferedWriter(filewriter));
            RelatorioPosProcessamento relatorio = new RelatorioPosProcessamento();
            String linha                        = new String();
            Vector parametros                   = new Vector();

            for (contRelatorio=0; contRelatorio < listaRelatorios.size(); contRelatorio++){
                    relatorio = (RelatorioPosProcessamento) listaRelatorios.get(contRelatorio);
                    linha = (contRelatorio + "\t" + relatorio.getNomeTipoRelatorio() + "\t"
                            +  relatorio.getCampo() + relatorio.getDirecao()+ "\t");

                    if (relatorio.getIdTipoRelatorio()==2)
                        linha = (linha + relatorio.getDirecaoOpcao() + "\t");

                    parametros = relatorio.getParametros();
                    for (contParametros=0; contParametros < parametros.size(); contParametros++)
                    {
                        linha = (linha + parametros.get(contParametros).toString() + "\t");
                    }
                    printwriter.println(linha);
                    System.out.println(linha);
            }
            printwriter.close();
            filewriter.close();
            return true;

        } catch (IOException ex) {
            Logger.getLogger(ControladorConfiguracoesProcessamento.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    
    private boolean gerarArquivoFieldsFDTD() {

        try {
            FileWriter filewriter = new FileWriter(this.enderecoEntradaFDTD + "_fields.isar");
            
            PrintWriter printwriter = new PrintWriter(new BufferedWriter(filewriter));
            // Imprime Primeiro Cabeçalho            
            printwriter.println("ex\t1");
            printwriter.println("ey\t1");
            printwriter.println("ez\t1");
            printwriter.println("hx\t1");
            printwriter.println("hy\t1");
            printwriter.println("hz\t1");
            printwriter.close();
            filewriter.close();
            return true;

        } catch (IOException ex) {
            Logger.getLogger(ControladorConfiguracoesProcessamento.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    
    public boolean verificaArquivosEntradaFEM(){
        boolean retorno = true;
        
        File arq1 = new File("Malha");
        File arq2 = new File("Malha-1");
        File arq3 = new File("Malha-2");
        File arq4 = new File("Malha-3");
        File arq5 = new File("Malha-4");
        if (!arq1.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo Malha não existe.");
            return false;
        }
        
        if (!arq2.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo Malha-1 não existe.");
            return false;
        }
        
         if (!arq3.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo Malha-2 não existe.");
            return false;
        }
        
         if (!arq4.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo Malha-3 não existe.");
            return false;
        }
        
         if (!arq5.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo Malha-4 não existe.");
            return false;
        }
        
        
        return retorno;
    }
    /*
     * Método que executa a geracao dos arquivos de configuração necessários ao 
     * processamento com o FDTD
     */

    public boolean configurarSimulacao() {
        if (discretizacaoSimulacao.size() != 3) {
            System.out.println("Erro: Inicializar corretamente os Limites da Simulação.");
            return false;
        } else if (nmax == 0) {
            System.out.println("Erro: informar a quantiade de passos de tempo da simulação");
            return false;
        } else {
            if (deltaSimulacao.size() != 3) {
                System.out.println("Erro: Inicializar corretamente os Delta da Simulação.");
                return false;
            }
        }
        // Verificacoes de existencia dos arquivos e se outros foram gerados corretamente
        if (limitesSimulacao ==null){
            System.out.println("Erro: Os limites da simulação não foram especificados.");
            return false;
        }
        File arq = new File(this.enderecoEntradaFDTD + "_config_pml.isar");
        if (!arq.exists()) { // se arquivo não existir   
            System.out.println("Erro: Arquivo de configuração da PML não existe.");
            return false;
        }
        if (gerarArquivoRelatorio() == false) {
            System.out.println("Erro: Arquivo de configuração dos relatórios de simulação não foi criado corretamente.");
            return false;
        }
        
        if (gerarArquivoFieldsFDTD() == false) {
            System.out.println("Erro: Arquivo de configuração do campos (Fields) não foi criado corretamente.");
            return false;
        }
        if (gerarArquivoConfigFDTD() == false) {
            System.out.println("Erro: Arquivo de configuração do domínio computacional (_config) não foi criado corretamente.");
            return false;
        }
        if(gerarArquivoFonteEletromagneticaFDTD()==false){
            System.out.println("Erro: Arquivo de configuração das Fontes Eletromagnéticas não foi criado corretamente.");
            return false;
        }
        
        return true;
    }

    /**
     * Atribui o caminho de entrada do FDTD
     * @param nome String
     */
    public void setNomeArquivoEntradaFDTD(String nome) {
        this.enderecoEntradaFDTD = nome;
    }

    /**
     * Retorna o caminho de Entrada do FDTD
     * @return nome String
     */
    public String getNomeArquivoEntradaFDTD() {
        return this.enderecoEntradaFDTD;
    }

    /**
     * Atribui o caminho de saida do FDTD
     * @param nome String
     */
    public void setNomeArquivoSaidaFDTD(String nome) {
        this.enderecoSaidaFDTD = nome;
    }

    /**
     * Retorna o caminho de Saida do FDTD
     * @return nome String
     */
    public String getNomeArquivoSaidaFDTD() {
        return this.enderecoSaidaFDTD;
    }

    /**
     * Atribui as dimensoes da cena de simulacao
     * @param dimensoes Vector
     */
    public void setLimitesDominioFDTD(Vertice[] dimensoes) {
        this.limitesSimulacao = dimensoes;
    }

    /**
     * Retorna os Limites da Simulacao
     * @return limites Vector
     */
    public Vertice[] getLimitesDominioFDTD() {
        return this.limitesSimulacao;
    }

    /**
     * Atribuir as dimensoes do dominio em X,Y,Z para a discretizacao
     * @param discretizar Vector
     */
    public void setDiscretizacaoDominioFDTD(Vector discretizar) {
        this.discretizacaoSimulacao = discretizar;
    }

    /**
     * Retorna as dimensoes de discretrizacao da simulacao
     * @return discretizar Vector
     */
    public Vector getDiscretizacaoDominioFDTD() {
        return this.discretizacaoSimulacao;
    }

    /**
     * Atribui a quantidade de passos de tempo a serem executados pelo FDTD
     * @param passos Int
     */
    public void setPassosTempo(int n) {
        this.nmax = n;
    }

    /**
     * Retorna a quantidade de passos de tempo a serem executados pela simulacao
     * @return tempo Int
     */
    public int getPassosTempo() {
        return this.nmax;
    }

    /**
     * Calcular e retornar os Delta Espaciais 3D
     */
    public Vector getDeltaFDTD() {       
        return this.deltaSimulacao;
    }

    /**
     * Atribuir os valores dos delta espaciais
     * @param delta Vector
     */
    public void setDeltaFDTD(Vector delta)
    {
        this.deltaSimulacao = delta;
    }

    /*
     * Gerar o arquivo referente as configuracoes do domínio da simulacao
     */
    private boolean gerarArquivoConfigFDTD() {

        try {
            FileWriter filewriter = new FileWriter(this.enderecoEntradaFDTD + "_config.isar");
            PrintWriter printwriter = new PrintWriter(new BufferedWriter(filewriter));

            // Imprime Primeiro Cabeçalho            
            printwriter.println("//---------------------------------------------------");
            printwriter.println("// UNICAMP-CPQD ELCTROMAGNETIC SIMULATOR");
            printwriter.println("//Arquivo de Configuração do Domínio Computacional");
            printwriter.println("//---------------------------------------------------");
            printwriter.println("                                                      ");

            //Inserido os dados das dimensoes do dominio FDTD
            printwriter.println("// Propriedades do domínio");
            printwriter.println("sx " + this.discretizacaoSimulacao.get(0));
            printwriter.println("sy " + this.discretizacaoSimulacao.get(0));
            printwriter.println("sz " + this.discretizacaoSimulacao.get(0));

            // Quantidade de passos de tempo
            printwriter.println("// Passos de tempo");
            printwriter.println("nmax " + this.nmax);

            // Delta Espacial
            double dx =Double.valueOf((Double) this.deltaSimulacao.get(0))/100.0;
            double dy =Double.valueOf((Double) this.deltaSimulacao.get(1))/100.0;
            double dz =Double.valueOf((Double) this.deltaSimulacao.get(2))/100.0;
            
            printwriter.println("// Delta Espacial da simulação");
            printwriter.println("dx\t" + dx);
            printwriter.println("dy\t" + dy);
            printwriter.println("dz\t" + dz);

            // Tipo de Arquivo (0-ASCII e 1-Binario) - Por enquanto apenas 0 está funcionando
            printwriter.println("//Tipo de arquivo de dados");
            printwriter.println("filetype\t0");

            printwriter.close();
            filewriter.close();
            return true;

        } catch (IOException ex) {
            Logger.getLogger(ControladorConfiguracoesProcessamento.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    /**
     * Recebe a listagem de fontes Eletromagneticas do Usuário
     * @param lista ListaFontes
     */
    public void setListaFontesEletromagneticas(ListaFontesEletromagneticas listaFonte) {
        this.listaFontes = listaFonte;
    }

    /**
     * Recebe a listagem de fontes Eletromagneticas Inseridas na Simulacao
     * @param lista ListaFontesSimulacao
     */
    public void setListaFontesEletromagneticasSimulacao(ListaFontesEletromagneticasSimulacao listaFonte) {
        this.listaFontesEletromagnetciasSimulacao = listaFonte;
    }

    /**
     * Gerador do arquivo de configuração das fontes eletromagneticas inseridas
     * na simulacao e adaptadas as malhas do FDTD 3D
     */
    private boolean gerarArquivoFonteEletromagneticaFDTD() {
        FonteEletromagneticaSimulacao fonteSimulacao;
        FonteEletromagnetica    fonte;  
        Vector parametros;
        int x,y,z;
        int cont, contParam;
        float vx, vy, vz;
        double dx, dy, dz;
        try {
            FileWriter filewriter = new FileWriter(this.enderecoEntradaFDTD + "_electromagneticsources.isar");
            PrintWriter printwriter = new PrintWriter(new BufferedWriter(filewriter));
            
            // Imprime o Cabeçalho do arquivo
            printwriter.println("// ----- Cadastramento de Fontes Eletromagnéticas Utilizadas no FDTD 3D");
            printwriter.println("idFonte\tidTipoFonte\tCampo\tDirecao\tx\ty\tz\tParametros");
            
            // Estrutura de Repeticao Principal, visando listar todas as fontes inseridas na simulacao
            // para a colocacao nas devidas posicoes da malha
            for (cont = 0; cont < this.listaFontesEletromagnetciasSimulacao.size(); cont++) {
                fonteSimulacao = new FonteEletromagneticaSimulacao();
                fonte          = new FonteEletromagnetica();
                fonteSimulacao = listaFontesEletromagnetciasSimulacao.getFonteSimulacao(cont);
                fonte          = listaFontes.getFonteIndex(fonteSimulacao.getIdType());
                if (fonte==null){
                    System.out.println("Erro: Índice do Tipo de Fonte da Simulação não existe.");
                    System.exit(0);
                }
                printwriter.print(String.valueOf(fonteSimulacao.getIdFonte())   + "\t\t");
                printwriter.print(String.valueOf(fonte.getIdType())    + "\t\t");
                if (fonte.getField().equals("Elétrico"))
                    printwriter.print("e\t");
                else if (fonte.getField().equals("Magnético"))
                    printwriter.print("m\t");
                else {
                    System.out.println("Erro: Campo Eletromagnético da Fonte é Inválido.");
                    System.exit(0);
                }                    
                printwriter.print(fonte.getDirection() + "\t");
                
                // Calculado e escrevendo a coordenada X da fonte eletromagnetica da simulacao
                vx = this.limitesSimulacao[0].getCoordenada(0);
                
                //dx = Double.valueOf(this.deltaSimulacao.get(0).toString());
                dx = Math.abs(this.limitesSimulacao[1].getCoordenada(0)- this.limitesSimulacao[0].getCoordenada(0))/Integer.valueOf(discretizacaoSimulacao.get(0).toString());              
                x = (int) (Math.abs(fonteSimulacao.getX() - vx)/dx) + Integer.valueOf(pml.get(0).toString());
                if (x==0) 
                    x++;
                printwriter.print(String.valueOf(x)+"\t");
                
                // Calculado e escrevendo a coordenada Y da fonte eletromagnetica da simulacao
                vy = this.limitesSimulacao[0].getCoordenada(1);
                //dy = Double.valueOf(this.deltaSimulacao.get(1).toString());
                dy = Math.abs(this.limitesSimulacao[1].getCoordenada(1)- this.limitesSimulacao[0].getCoordenada(1))/Integer.valueOf(discretizacaoSimulacao.get(1).toString());
                y = (int) (Math.abs(fonteSimulacao.getY() - vy)/dy) + Integer.valueOf(pml.get(2).toString());
                if(y==0)
                    y++;                
                printwriter.print(String.valueOf(y)+"\t");
                
                // Calculado e escrevendo a coordenada Z da fonte eletromagnetica da simulacao
                vz = this.limitesSimulacao[0].getCoordenada(2);
                //dz = Double.valueOf(this.deltaSimulacao.get(2).toString());                
                dz = Math.abs(this.limitesSimulacao[1].getCoordenada(2)- this.limitesSimulacao[0].getCoordenada(2))/Integer.valueOf(discretizacaoSimulacao.get(2).toString());
                z = (int) (Math.abs(fonteSimulacao.getZ() - vz)/dz) + Integer.valueOf(pml.get(4).toString());
                if(z==0)
                    z++;          
                printwriter.print(String.valueOf(z)+"\t");
                
                parametros = new Vector();
                parametros = fonte.getParameters();
                for (contParam=0; contParam < parametros.size(); contParam++){
                    printwriter.print(parametros.get(contParam).toString()+"\t");
                }
                printwriter.print("\n");
            }
            printwriter.close();
            filewriter.close();
            return true;
        } catch (IOException ex) {
            Logger.getLogger(ControladorConfiguracoesProcessamento.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    
    
    /**
     * Atribui a quantidade de camadas PML configuradas para a simulacao
     * @param pml Vector
     */
    public void setPml(Vector pml){
        this.pml = pml;
    }
   
    /**
     * Receber o vetor com todos os relatorios cadastrados
     * @param relatorios Vector
     */
    public void setRelatorios(Vector valor) {
        this.listaRelatorios = valor;
    }


    public void salvarRelatorios(){
        gerarArquivoRelatorio();
    }
}
